<?php
/**
 * 通用文字识别
 */
namespace soa\ocr\baiduOcr;
use artisan\db;
use soa\ocr\sinosecuOcr\sinosecuOcr;

class generalOcr{
    /**
     * 通用文字识别基础班，不含位置信息
     * @param $img
     * @param string $ocrWhat
     *     $ocrWhat = 'allWords' 返回所有文本即可
     * @return array
     */
    public static function generalBasicOcr($img, $ocrWhat='allWords'){
        if(empty($img)){
            raise(1009, '没有需要识别的图像！');
        }
        $return = [];
        $retArr = baiduOcr::generalBasic($img);//百度通用文字识别（基础班）

        if(//返回值正常
            isset($retArr['words_result']) &&
            !empty($retArr['words_result']) &&
            is_array($retArr['words_result'])
        ){
            switch ($ocrWhat){
                case 'allWords':
                    return $retArr;
                    break;
            }
        }
        return $return;
    }

    /**
     * 身份证识别（使用普通识别接口和使用百度身份证识别接口）
     * @param $img
     * @param bool $isFront
     * @param array $options
     * @return array
     */
    public static function idCardOCR($img, $isFront = true, $options = ['detect_direction'=>'true']){
        if(empty($img)){
            raise(1009, '没有需要识别的图像！');
        }
        $return = [];
        $ocrStartTime = time();
        $isGeneralBasic = 0;//0-baiduOcr::idCardOCR；1-baiduOcr::generalBasic；2-sinosecuOcr::idCardOcr
        $rand = rand(0,100);
        if($isFront && $rand < -1){//身份证正面并且 5%比例 使用通用接口
//        if(false){
            $supplier = 'baiduBasic';
//            $img = '/upload/order2/realname/ocr/2017_10/20/159e9c48923f52015489222.jpg';
            if(stripos($img, 'http') === false){
                $img = 'http://upload.kuaidihelp.com/'.substr($img, 7);
            }
            $ret = baiduOcr::generalBasic($img);
            $isGeneralBasic = 1; 
        }elseif($rand >= 0 && $rand <= 100){
//         }elseif(false){
            $supplier = 'zhongAnWeiLai';
            if(stripos($img, 'http') === false){
                $img = 'http://upload.kuaidihelp.com/'.substr($img, 7);
            }
            $frontStyle = $isFront ? 2 : 3;//2-正面；3-背面；101-未知
            $ret = sinosecuOcr::idCardOcr($img, $frontStyle);
            $isGeneralBasic = 2;
        }else{
            $supplier = 'baiduIdCard';

            list($width, $height) = getimagesize($img);// /upload/order2/realname/ocr/2017_10/20/159e9c48923f52015489222.jpg';
            if($width > 3000 || $height > 3000){
                $imgPathTemp = self::resizeImage($img);
                $img = empty($imgPathTemp) ? $img : $imgPathTemp;
            }

            $ret = baiduOcr::idCardOCR($img, $isFront, $options);
        }

        if(//云脉ocr返回的结果
            isset($ret['data']['cardsinfo']['card']['item'])
        ){
            if($isFront){
                $return['name'] = $ret['data']['cardsinfo']['card']['item'][1]? : '';
                $return['birthday'] = str_replace('-','',$ret['data']['cardsinfo']['card']['item'][4])? : '';
                $return['sex'] = $ret['data']['cardsinfo']['card']['item'][2]? : '';
                $return['address'] = $ret['data']['cardsinfo']['card']['item'][5]? : '';
                $return['id'] = $ret['data']['cardsinfo']['card']['item'][6]? : '';
                $return['nation'] = $ret['data']['cardsinfo']['card']['item'][3]? : '';
            }else{
                $return['startDate'] = str_replace('-','',$ret['data']['cardsinfo']['card']['item'][3])? : '';
                $return['endDate'] = str_replace('-','',$ret['data']['cardsinfo']['card']['item'][4])? : '';
                $return['policeStation'] = $ret['data']['cardsinfo']['card']['item'][1]? : '';
            }
        }
//var_dump($return);
        if(//百度类接口返回的结果
            isset($ret['words_result']) &&
            is_array($ret['words_result'])
        ){
            if($isFront){//识别正面
                if($isGeneralBasic){//百度通用识别接口返回的
//                    $return = $ret['words_result'];
                    //始名胡皓杰' (length=15)
                    //性别男民族汉
                    //出生1999年1月27日
                    //住址乌鲁木齐市新市区北站二
                    //路9号平3栋2号
                    //个回↓
                    //公民身份号码650104199901274715
                    $wordsArr = array_column($ret['words_result'], 'words');
                    $nameNum = $sexNum = $nationNum =0;
                    foreach($wordsArr as $num=>$words){
                        preg_match_all('/(姓名(?<name1>.*)?)|(姓(.{3})?(?<name2>.*)?)|((.{3})?名(?<name3>.*)?)/', $words, $matchs);
                        //第一次获取name1
                        $nameArr = array_filter($matchs['name1']);
                        if(isset($nameArr[0]) && $nameArr[0]){
                            $return['name'] = $nameArr[0];
                            $nameNum = $num;
                            break;
                        }
                        //第二次获取name2
                        $nameArr = array_filter($matchs['name2']);
                        if(isset($nameArr[0]) && $nameArr[0]){
                            $return['name'] = $nameArr[0];
                            $nameNum = $num;
                            break;
                        }
                        //第三次获取name3
                        $nameArr = array_filter($matchs['name3']);
                        if(isset($nameArr[0]) && $nameArr[0]){
                            $return['name'] = $nameArr[0];
                            $nameNum = $num;
                            break;
                        }
                    }

                    $wordsArrAfterName = array_slice($wordsArr, $nameNum+1);
                    //性别男民族汉
                    foreach($wordsArrAfterName as $num=>$words){
                        preg_match_all('/(性别(?<sex1>.{3})?)|(性.{3}(?<sex2>.{3})?)|(.{3}别(?<sex3>.{3})?)/', $words, $matchs);
                        //第一次获取sex1
                        $sexArr = array_filter($matchs['sex1']);
                        if(isset($sexArr[0]) && $sexArr[0] && in_array($sexArr[0], ['男', '女'])){
                            $return['sex'] = $sexArr[0];
                            $sexNum = $num;
                            break;
                        }
                        //第二次获取sex2
                        $sexArr = array_filter($matchs['sex2']);
                        if(isset($sexArr[0]) && $sexArr[0] && in_array($sexArr[0], ['男', '女'])){
                            $return['sex'] = $sexArr[0];
                            $sexNum = $num;
                            break;
                        }
                        //第三次获取sex3
                        $sexArr = array_filter($matchs['sex3']);
                        if(isset($sexArr[0]) && $sexArr[0] && in_array($sexArr[0], ['男', '女'])){
                            $return['sex'] = $sexArr[0];
                            $sexNum = $num;
                            break;
                        }
                    }

                    foreach($wordsArrAfterName as $num=>$words){
                        preg_match_all('/(民族(?<nation1>.*)?)|(民.{3}(?<nation2>.*)?)|(.{3}族(?<nation3>.*)?)/', $words, $matchs);
                        //第一次获取nation1
                        $nationArr = array_filter($matchs['nation1']);
                        if(isset($nationArr[0]) && $nationArr[0]){
                            $return['nation'] = $nationArr[0];
                            $nationNum = $num;
                            break;
                        }
                        //第二次获取nation2
                        $nationArr = array_filter($matchs['nation2']);
                        if(isset($nationArr[0]) && $nationArr[0]){
                            $return['nation'] = $nationArr[0];
                            $nationNum = $num;
                            break;
                        }
                        //第三次获取nation3
                        $nationArr = array_filter($matchs['nation3']);
                        if(isset($nationArr[0]) && $nationArr[0]){
                            $return['nation'] = $nationArr[0];
                            $nationNum = $num;
                            break;
                        }
                    }
                    //住址乌鲁木齐市新市区北站二
                    foreach($wordsArrAfterName as $num=>$words){
                        preg_match_all('/(住址(?<address1>.*)?)|(住.{3}(?<address2>.*)?)|(.{3}址(?<address3>.*)?)/', $words, $matchs);
                        //第一次获取address1
                        $addressArr = array_filter($matchs['address1']);
                        if(isset($addressArr[0]) && $addressArr[0]){
                            $return['address'] = $addressArr[0];
                            $addressNum = $nameNum+1+$num;
                            break;
                        }
                        //第二次获取address2
                        $addressArr = array_filter($matchs['address2']);
                        if(isset($addressArr[0]) && $addressArr[0]){
                            $return['address'] = $addressArr[0];
                            $addressNum = $nameNum+1+$num;
                            break;
                        }
                        //第三次获取address3
                        $addressArr = array_filter($matchs['address3']);
                        if(isset($addressArr[0]) && $addressArr[0]){
                            $return['address'] = $addressArr[0];
                            $addressNum = $nameNum+1+$num;
                            break;
                        }
                    }

                    //公民身份号码650104199901274715
                    foreach($wordsArr as $num=>$words){
                        preg_match_all('/(.{3}|公)?(.{3}|民)?(.{3}|身)?(.{3}|份)?(.{3}|号)?(.{3}|码)?(?<id>\d{17,18}(x|X)?)/', $words, $matchs);
                        $idArr = array_filter($matchs['id']);
                        if(isset($idArr[0]) && $idArr[0]){
                            $return['id'] = $idArr[0];
                            $idNum = $num;
                            break;
                        }
                    }
                    if(
                        isset($idNum) &&
                        isset($addressNum) &&
                        $idNum-$addressNum > 1
                    ){
                        for($i=$addressNum+1;$i<$idNum;$i++){
                            $return['address'] = isset($wordsArr[$i]) ? $return['address'].$wordsArr[$i] : $return['address'];
                        }
                    }


                    if(isset($return['id']) && $return['id']){
                        preg_match_all('/\d{6}(?<birthday>\d{8})\d{3,6}(x|X)?$/', $return['id'], $matchs);
                        $birthdayArr = array_filter($matchs['birthday']);
                        if(isset($birthdayArr[0]) && $birthdayArr[0]){
                            $return['birthday'] = $birthdayArr[0];
                        }
                    }

                    //出生1999年1月27日
                    if(empty($return['birthday'])){//身份证未匹配出，再尝试一次
                        foreach($wordsArrAfterName as $num=>$words){
                            preg_match_all('/(出生|.{3}生|出.{3})(?<year>\d{4})(年|.{3})/', $words, $matchs);
                            $yearArr = array_filter($matchs['year']);
                            if(isset($yearArr[0]) && $yearArr[0]){
                                $return['birthday'] = $yearArr[0];
                                break;
                            }
                        }
                        foreach($wordsArrAfterName as $num=>$words){
                            preg_match_all('/年(?<month>\d{1,2})月/', $words, $matchs);
                            $monthArr = array_filter($matchs['month']);
                            if(isset($monthArr[0]) && $monthArr[0]){
                                $return['birthday'] = strlen($monthArr[0])==1 ? $return['birthday'].'0'.$monthArr[0] : $return['birthday'].$monthArr[0];
                                break;
                            }
                        }
                        foreach($wordsArrAfterName as $num=>$words){
                            preg_match_all('/月(?<day>\d{1,2})日/', $words, $matchs);
                            $dayArr = array_filter($matchs['day']);
                            if(isset($dayArr[0]) && $dayArr[0]){
                                $return['birthday'] = strlen($dayArr[0])==1 ? $return['birthday'].'0'.$dayArr[0] : $return['birthday'].$dayArr[0];
                                break;
                            }
                        }
                    }
                }else{//百度身份证接口返回的
                    $return['name'] = $ret['words_result']['姓名']['words']? : '';
                    $return['birthday'] = $ret['words_result']['出生']['words']? : '';
                    $return['sex'] = $ret['words_result']['性别']['words']? : '';
                    $return['address'] = $ret['words_result']['住址']['words']? : '';
                    $return['id'] = $ret['words_result']['公民身份号码']['words']? : '';
                    $return['nation'] = $ret['words_result']['民族']['words']? : '';
                }
            }else{//识别反面
                $return['startDate'] = $ret['words_result']['签发日期']['words']? : '';
                $return['endDate'] = $ret['words_result']['失效日期']['words']? : '';
                $return['policeStation'] = $ret['words_result']['签发机关']['words']? : '';
            }
        }

        $isNeedPay = false;//是否需要计费（支付给百度的费用，对账用）
        if(
            !empty($return) ||
            (isset($ret['error_code']) && $ret['error_code'] == 216633) ||
            (isset($ret['error_code']) && $ret['error_code'] == 216631)
        ){
            $isNeedPay = true;
        }

        $insertData = [
            'timeout'       => time() - $ocrStartTime,//调用接口耗时
            'ocr_time'      => date('Y-m-d H:i:s'),//识别时间
            'pic_path'      => $img,//图片路径
            'original_data' => json_encode($ret, JSON_UNESCAPED_UNICODE),//接口原始返回结果json格式
            'result'        => json_encode($return, JSON_UNESCAPED_UNICODE),//处理后的返回结果json格式
            'supplier'      => $supplier,//调用的百度的接口
            'status'        => !empty($return) ? 'success' : 'fail',//是否成功
            'is_need_pay'   => $isNeedPay ? 1 : 0,//百度那边是否需要扣费  1-表示是使用百度身份证接口识别收费的
            'is_front'      => $isFront ? 1 : 0,//是否正面 1-正面；0-反面
        ];
        if($isGeneralBasic == 1){
            $insertData['is_need_pay'] = 2;//表示是使用通用接口识别收费的
        }elseif($isGeneralBasic == 2){
            $insertData['is_need_pay'] = 3;//表示是使用云脉接口
        }
        $thermalPaperDBObj = db::connect('users')->table('tbl_idcard_ocr');

        $ret = $thermalPaperDBObj->insert($insertData);
        if(!$ret){
            logDebug(json_encode([
                'timeOut'    => time() - $ocrStartTime,//调用接口耗时
                'return'     => $ret,//原始返回值
                'insertData' => $insertData,//待入库参数
            ], JSON_UNESCAPED_UNICODE), 'kdhelp_IdCardOcr_insertErr', true);
        }



        //返回的姓名字段过滤掉垃圾字符  比如：~！@#￥%……&*（）；只保留中文
        if(isset($return['name'])){
//            $logArr['1'] = $return['name'];
//            $logArr['2'] = $return['name'] = preg_replace('/[^\x{4e00}-\x{9fa5}]/u', '', $return['name']);
//            logDebug($logArr, 'idCardOcrErrLog');
            $return['name'] = preg_replace('/[^\x{4e00}-\x{9fa5}]/u', '', $return['name']);
        }

        return $return;
    }


    /**
     * 图像缩放，宽度缩到1500，高度等比缩放
     * @param $file
     * @return bool
     */
    public static function resizeImage($file) {
        //$file = input::any('imgPath');
        list($width, $height) = getimagesize($file);
        $w=1500;
        $h=($w / $width) * $height;//根据情况实际情况等比缩放
        $r = $width / $height;
        if ($w / $h > $r) {
            $newwidth = $h * $r;
            $newheight = $h;
        } else {
            $newheight = $w / $r;
            $newwidth = $w;
        }
        $src = imagecreatefromjpeg($file);
        $dst = imagecreatetruecolor($newwidth, $newheight);
        imagecopyresampled($dst, $src, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
        $newPath=str_replace('.','_small.',$file);

        if(stripos($newPath, 'gif') !== false){
            $isOk=imagegif($dst,$newPath);
        }elseif(stripos($newPath, 'png') !== false){
            $isOk=imagepng($dst,$newPath);
        }else{
            $isOk=imagejpeg($dst,$newPath);
        }

        return $isOk?$newPath:false;
    }
}
